package com.xlserver.component;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
//import com.xlserver.domain.Message;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.xlserver.dao.StateMapper;
import com.xlserver.domain.State;
import com.xlserver.service.MessageService;
//import netscape.javascript.JSObject;
import com.xlserver.service.MessageService;
import com.xlserver.util.Base64ToMultipartFile;
import com.xlserver.util.ImageParser;
import com.xlserver.util.model.Msg;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;


/**
 * @author websocket服务
 */
@ServerEndpoint(value = "/websocket/{from}/to/{to}")
@Component
public class WebSocketServer {
    //    本质原因：spring管理的都是单例（singleton）和 websocket （多对象）相冲突。
//    故而不能使用@Autowired注入messageService
    private static MessageService messageService;
    private static ImageParser imageParser;
    private static StateMapper stateMapper;
    @Autowired
    public void setStateMapper(StateMapper stateMapper){
        WebSocketServer.stateMapper = stateMapper;
    }
    @Autowired
    public void setChatService(MessageService messageService) {
        WebSocketServer.messageService = messageService;
    }

    @Autowired
    public void setImageParser(ImageParser imageParser) {
        WebSocketServer.imageParser = imageParser;
    }

    public static final Map<String, Session> sessionMap = new ConcurrentHashMap<>();
    //设置存储会话的map的键from-to
    private String makeKey(String from, String to) {
        return from+"-"+to;
    }

    /**
     *  返回hid，每次涉及会话信息持久化的接口调用时，都要传回hid
     */
    @OnOpen
    public void onOpen(Session session,
                       @PathParam("from") String from,
                       @PathParam("to") String to) {
        sessionMap.put(makeKey(from, to), session);
        //前端格式：c_cid；u_uid
        Map<String,Integer> users = parseUsers(from,to);
        int uid = users.get("uid");
        int cid = users.get("cid");
        System.out.println("from:"+from);
        System.out.println("to:"+to);
        //判断咨询师在线，不在线则不建立会话，直接返回
        if (stateMapper.selectById(cid).getState() == -1){
            System.out.println("咨询师不存在");
            sendMessage("failure",session);//不存在返回failure
            return;
        }
        //建立会话，返回历史记录，调用sendmsg返回历史记录
        messageService.createChat(uid,cid).forEach((mes)->{
            JSONObject msg = (JSONObject) mes;
            sendMessage(msg.toString(), session);
        });
        //若为user连入，通知其等待，若为咨询师连入，通知用户：咨询师已就位
        if (parseUser(from) == uid){
            sendMessage("请等待",session);
        }
        else {
            Session userSession = sessionMap.get(makeKey(to, from));
            if (userSession != null)
            sendMessage("hello",userSession);
            sendMessage("hello",session);
            stateMapper.update(null,new UpdateWrapper<State>().eq("id",cid).set("state",1));//设置为忙碌
        }
        System.out.println("新连接建立："+from+" to "+to);
    }

    @OnClose
    public void onClose(Session session,
                        @PathParam("from") String from,
                        @PathParam("to") String to) {
        sessionMap.remove(makeKey(from, to));
        Map<String,Integer> users = parseUsers(from,to);
        int uid = users.get("uid");
        int cid = users.get("cid");
        messageService.closeChat(messageService.getHid(uid,cid));//关闭会话
        stateMapper.update(null,new UpdateWrapper<State>().eq("id",cid).set("state",0));//设置为空闲
        System.out.println(makeKey(from, to) + "的连接关闭");
    }

    //前端传入base64，转换为MultipartFile
    //Websocket中maxMessageSize默认是8K，接收的图片大于8K导致接收失败
    // 解决方法：适当加大maxMessageSize，此处改为10m
    @OnMessage(maxMessageSize = 10485760)
    public void onMessage(String message,
                          Session session,
                          @PathParam("from") String from,
                          @PathParam("to") String to) throws IOException {
        //解析信息
        Msg msg = parseMessage(message);
        //获得uid，cid
        Map<String,Integer> users = parseUsers(from,to);
        int uid = users.get("uid");
        int cid = users.get("cid");
        //当前会话id
        int hid = messageService.getHid(uid,cid);
        Session toSession = sessionMap.get(makeKey(to, from));
        if (toSession != null) {
            if (msg.getType() == 1){//插入图片
                messageService.insertPhoto(msg.getMessage(),parseUser(from),parseUser(to),hid);
            }
            else if(msg.getType() == 0){//插入文本
                messageService.insertMsg(msg.getMessage(), parseUser(from), parseUser(to), hid);
            }
            else if(msg.getType() == 2){//插入转发的历史记录
                messageService.insertHistory(msg.getMessage(), parseUser(from), parseUser(to), hid);
            }
            message = encapsulateMsg(msg,from,to).toJSONString();
            this.sendMessage(message, session);
            this.sendMessage(message, toSession);
        } else {
            System.out.println("发送失败,会话不存在");
        }
    }
    //封装消息
    private JSONObject encapsulateMsg(Msg msg,String from,String to){
        JSONObject obj = new JSONObject();
        SimpleDateFormat ft = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        obj.put("message", msg.getMessage());
        obj.put("from", parseUser(from));
        obj.put("to", parseUser(to));
        obj.put("time", ft.format(System.currentTimeMillis()));
        obj.put("type",msg.getType());
        return obj;
    }
    @OnError
    public void onError(Session session, Throwable error) {
        System.out.println("发生错误");
        error.printStackTrace();
    }

    private void sendMessage(String message, Session toSession){
        try {
            toSession.getBasicRemote().sendText(message);
        } catch (Exception e) {
            System.out.println("服务端发送消息给客户端失败");
        }
    }

    /**
     * 将from，to转换为cid，uid
     * @return {"uid":   ; "cid":   }
     */
    private Map<String,Integer> parseUsers(String id1,String id2){
        Map<String,Integer> res = new HashMap<>();
        String[] user1 = id1.split("_");
        String[] user2 = id2.split("_");
        if ("uid".equals(user1[0])){
            res.put("uid",Integer.parseInt(user1[1]));
            res.put("cid",Integer.parseInt(user2[1]));
        }
        else {
            res.put("uid",Integer.parseInt(user2[1]));
            res.put("cid",Integer.parseInt(user1[1]));
        }
        return res;
    }

    /**
     *将uid_1的格式转为1
     */
    private int parseUser(String user){
        String[] res = user.split("_");
        return Integer.parseInt(res[1]);
    }

    /**
     *base64格式转为multipartfile格式
     */
    private MultipartFile convertBaseToMultipartFile(String base64){
        final String[] base64Array = base64.split(",");
        String dataUir, data;
        if (base64Array.length > 1) {
            dataUir = base64Array[0];
            data = base64Array[1];
        } else {
            //根据你base64代表的具体文件构建
            dataUir = "data:image/jpg;base64";
            data = base64Array[0];
        }
        return new Base64ToMultipartFile(data, dataUir);
    }
    /**
     * 对前端传递消息进行解析
     */
    private Msg parseMessage(String message) throws IOException {
        //获取消息
        JSONObject msg = JSONObject.parseObject(message);
        //获取消息内容
        String data = (String) msg.get("msg");
        //获取消息类型，图片为1，文本为0
        int type = (int) msg.get("type");
        //对图片进行处理
        if (type == 1){
            data = ImageParser.saveImage(convertBaseToMultipartFile(data));
        }
        return new Msg(type,data);
    }

}

